package com.bigzero.workflow.common.filter;

import com.bigzero.workflow.common.exception.WorkflowException;
import com.bigzero.workflow.common.model.TokenAuthInfo;
import com.bigzero.workflow.common.model.TokenInfo;
import com.bigzero.workflow.common.model.UserPermInfo;
import com.bigzero.workflow.common.utils.SpringContextUtil;
import com.bigzero.workflow.modules.system.service.UserCacheService;
import com.bigzero.workflow.modules.system.service.impl.UserCacheServiceImpl;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * token认证过滤器
 *
 * @author fanxinxiong
 * @since 2024-06-07
 */
@Slf4j
public class TokenAuthFilter extends BasicAuthenticationFilter {

    /**
     * 是否拦截header
     */
    @Value("${workflow.header.intercept}")
    private boolean intercept;

    public TokenAuthFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String token = getRequestToken(request);
        //请求头中没有Token信息则直接放行
        if(StringUtils.isBlank(token)){
            if(intercept == false){
                String superAdministrator = "admin";
                TokenInfo tokenInfo = new TokenInfo();
                tokenInfo.setId("1");
                tokenInfo.setUsername(superAdministrator);
                tokenInfo.setIsSys(1);
                UserPermInfo userPermInfo = new UserPermInfo();
                userPermInfo.setUsername(superAdministrator);
                //认证授权
                doAuthorization(tokenInfo, userPermInfo, "none");
            }
            chain.doFilter(request, response);
            return;
        }
        UserCacheService userCacheService = SpringContextUtil.getBean(UserCacheServiceImpl.class);
        TokenInfo tokenInfo = userCacheService.getTokenInfo(token);
        //System.out.println(JSON.toJSONString(tokenInfo));
        if(tokenInfo == null){
            throw new WorkflowException("未认证", 401);
        }
        UserPermInfo userPermInfo = userCacheService.getUserPermInfoByTokenInfo(tokenInfo);
        userPermInfo = Optional.ofNullable(userPermInfo).orElse(new UserPermInfo());

        //认证授权
        doAuthorization(tokenInfo, userPermInfo, token);
        chain.doFilter(request, response);
    }

    /**
     * 认证授权
     * @param tokenInfo
     * @param userPermInfo
     * @param token
     */
    private void doAuthorization(TokenInfo tokenInfo, UserPermInfo userPermInfo, String token){
        List<SimpleGrantedAuthority> authorityList = new ArrayList<>();
        //角色编码集合
        List<String> roleCodeList = userPermInfo.getRoleCodeList();
        roleCodeList = Optional.ofNullable(roleCodeList).orElse(new ArrayList<>());
        //设置角色
        roleCodeList.forEach(r->{
            authorityList.add(new SimpleGrantedAuthority("ROLE_" + r));
        });
        //权限标识集合
        List<String> permissionIdList = userPermInfo.getPermissionIdList();
        permissionIdList = Optional.ofNullable(permissionIdList).orElse(new ArrayList<>());
        //设置权限
        permissionIdList.forEach(p->{
            authorityList.add(new SimpleGrantedAuthority(p));
        });
        //配置token认证用户的权限
        UsernamePasswordAuthenticationToken userAuthorization = new UsernamePasswordAuthenticationToken(tokenInfo.getUsername(), token, authorityList);
        TokenAuthInfo tokenAuthInfo = new TokenAuthInfo(tokenInfo.getUsername(), token, authorityList);
        tokenAuthInfo.setUsername(tokenInfo.getUsername());
        tokenAuthInfo.setToken(token);
        tokenAuthInfo.setIsSys(tokenInfo.getIsSys());
        userAuthorization.setDetails(tokenAuthInfo);
        SecurityContextHolder.getContext().setAuthentication(userAuthorization);
        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(tokenInfo.getUsername());
    }

    /**
     * 解析token
     *
     * @param request jwt
     * @return token中的用户信息
     */
    private String getRequestToken(HttpServletRequest request){
        return request.getHeader("token");
    }

    /**
     * 获取用户头信息
     * @param request jwt
     * @return token中的用户信息
     */
    private String getUserHeader(HttpServletRequest request){
        return request.getHeader("User");
    }
}
